﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Configuration;
using Argos.Activities.MessageDelivery;
using Argos.Collections;
using Argos.Data.Model;
using System.Text.RegularExpressions;

namespace Argos.Windows.Forms
{
	[DisplayName("Alert Message Viewer")]
	[Description("Displays a User Interface that allows the user to view alerts.")]
	public partial class AlertMessageViewer: UserControl
	{

		public AlertMessageViewer()
		{
			InitializeComponent();
		}

		#region public IList<AlertMessage> Items { get; }

		private object ItemsLock = new object();

		private EventfulList<AlertMessage> _Items;

		/// <summary>
		/// Retuns the list of items viewed in the alert message viewer.
		/// </summary>
		[Browsable(false)]
		public IList<AlertMessage> Items
		{
			get
			{
				if (null == _Items)
				{
					_Items = new EventfulList<AlertMessage>();
					_Items.Cleared += delegate(object sender, EventArgs e)
					{
						try
						{
							this.AlertsTree.Nodes.Clear();
						}
						catch { }
					}
					;
					_Items.ItemAdded += delegate(object sender, ItemEventArgs<AlertMessage> e)
					{
						try
						{
							this.AlertsTree.Invoke((Action<AlertMessage>)this.AddAlertNode, e.Item);
						}
						catch { }
					};

					_Items.ItemRemoved += delegate(object sender, ItemEventArgs<AlertMessage> e)
					{
						try
						{
							this.AlertsTree.Invoke((Action<AlertMessage>)this.RemoveAlertNode, e.Item);
						}
						catch { }
					};

					_Items.ItemSet += delegate(object sender, ItemEventArgs<AlertMessage> e)
					{
						try
						{
							this.AlertsTree.Invoke((Action)this.ReloadTree);
						}
						catch { }
					};

				}
				return _Items;
			}
		}

		#endregion



		protected override void OnLoad(EventArgs e)
		{
			base.OnLoad(e);
			this.SplitContainer.SplitterDistance = Settings.Default.SplitterDistance;

			this.AlertBodyBrowser.Navigate("about:blank");
			this.ReloadTree();

			this.SplitContainer.SplitterMoved += this.SplitContainer_SplitterMoved;
		}



		private void AddAlertNode(AlertMessage alert)
		{
			TreeNode targetNode = this.AlertsTree.Nodes.Cast<TreeNode>().FirstOrDefault(
				delegate(TreeNode node)
				{
					if (node.Tag is Target)
					{
						return ((Target)node.Tag).Id == alert.Target.Id;
					}
					return false;
				}
			);

			if (null == targetNode)
			{
				targetNode = new TreeNode(alert.Target.Name);
				targetNode.Tag = alert.Target;
				targetNode.ToolTipText = alert.Target.Description;
				targetNode.ImageKey = "Target";
				targetNode.SelectedImageKey = "Target";
				this.AlertsTree.Nodes.Add(targetNode);
			}

			Exception ex = alert.RawData.FirstOrDefault(o => o is Exception) as Exception;

			TreeNode alertNode = new TreeNode(string.Format("{0:G} {1}", alert.CreatedDate.ToLocalTime(), alert.AlertType));
			alertNode.ToolTipText = string.Format("{0} at {1:R}, local time {2:G}{3}", alert.AlertType, alert.CreatedDate.ToUniversalTime(), alert.CreatedDate.ToLocalTime(), null != ex ? " - " + ex.Message : string.Empty);
			alertNode.Tag = alert;
			alertNode.ImageKey = alert.AlertType.ToString();
			alertNode.SelectedImageKey = alertNode.ImageKey;
			targetNode.Nodes.Add(alertNode);

			if (null == this.AlertsTree.SelectedNode)
			{
				targetNode.Expand();
				this.AlertsTree.SelectedNode = alertNode;
			}
		}

		private void ReloadTree()
		{
			this.AlertsTree.Nodes.Clear();

			lock (this.ItemsLock)
			{
				foreach (var item in this.Items)
				{
					this.AddAlertNode(item);
				}
			}
		}

		private void RemoveAlertNode(AlertMessage alert)
		{
			TreeNode removeNode = null;

			lock (this.ItemsLock)
			{
				foreach (TreeNode node in this.AlertsTree.Nodes)
				{
					if (object.Equals(node.Tag, alert))
					{
						removeNode = node;
						break;
					}
				}
			}

			if (null != removeNode)
				this.AlertsTree.Nodes.Remove(removeNode);
		}

		private void ShowSelectedNode()
		{
			this.AlertBodyBrowser.Document.Write("<html><body></body></html>");

			if (null != this.AlertsTree.SelectedNode)
			{
				StringBuilder sb = new StringBuilder();
				sb.Append("<html><head><style>label { font-weight: bold; }</style></head><body><pre>");

				if (this.AlertsTree.SelectedNode.Tag is Target)
				{
					Target t = (Target)this.AlertsTree.SelectedNode.Tag;

					sb.AppendFormat("<label>Name:</label> {0}\r\n", t.Name);
					sb.AppendFormat("<label>Description:</label> {0}\r\n", t.Description);
					sb.AppendFormat("<label>Monitoring Type:</label> {0}\r\n", t.MonitoringWorkflowType);
					sb.AppendFormat("<label>Test Activity:</label> {0}\r\n", t.Test.ActivityType);
				}
				else if (this.AlertsTree.SelectedNode.Tag is AlertMessage)
				{
					AlertMessage msg = (AlertMessage)this.AlertsTree.SelectedNode.Tag;
					if (!string.IsNullOrEmpty(msg.Body))
						sb.Append(msg.Body.Replace("\n", "\r\n"));

				}

				sb.Append("</pre></body></html>");

				this.AlertBodyBrowser.DocumentText = Regex.Replace(sb.ToString(), @"http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?", (m) => (string.Format(@"<a href=""{0}"" target=""_blank"">{0}</a>", m.Value)));
			}
		}

		private void SplitContainer_SplitterMoved(object sender, SplitterEventArgs e)
		{
			Settings.Default.SplitterDistance = this.SplitContainer.SplitterDistance;
			Settings.Default.Save();
		}

		private void AlertsTree_AfterSelect(object sender, TreeViewEventArgs e)
		{
			this.ShowSelectedNode();
		}



		private class Settings : ApplicationSettingsBase
		{

			public static Settings Default = (Settings)ApplicationSettingsBase.Synchronized(new Settings());

			[UserScopedSetting]
			[DefaultSettingValue("100")]
			public int SplitterDistance
			{
				get { return (int)this["SplitterDistance"]; }
				set { this["SplitterDistance"] = value; }
			}

		}

	}
}
